Server Function 可以在 Client Component 和 Server Component 中使用。
如果 Server Function 在 Client Component 使用要非常小心,有可能將機密資訊傳到 Client 端,建議先不要在 production 環境使用。
除此之外,還有另一種使用方式是和 React 19 新的表單功能使用。當 Server Function 傳給 action
props 或在 action
使用,又被稱做 Server Action。
在 React 中的 <form>
元素的 action
prop 可以接收 URL 或函數。傳入 URL 時,表單將像標準 HTML 一樣提交。但傳入函數時,該函數會負責處理表單的提交行為。這就可以取代傳統的事件處理,如 onSubmit
。
使用範例:
export default function Search() {
function search(formData: FormData) {
const query = formData.get("query");
//... 其他邏輯
}
return (
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}
在 action
的函數中,表單提交的內容會透過 FormData 格式傳遞。
除了 元素上的 action
prop 外,React 也允許在 、 和 元素上使用 formAction prop。formAction 會覆蓋掉父層 的 action 設定,同樣可以傳入 URL 或函數來處理提交邏輯。
另外要注意的是,無論在 中指定了什麼 method,當傳遞函數給 action
或 formAction
時,表單的 HTTP method 始終為 POST。
有一個重要的好處:即使 JavaScript 被禁用,表單依然能正常提交。這意味著你可以使用 Server Components 來處理表單提交,而不依賴 JavaScript 事件,如 onSubmit
。
為了更好的管理 action
相關的狀態, React 提供了許多相關的 Hook。
useActionState
是 React 19 的 Hook,用來管理表單提交的狀態。根據表單操作的結果來更新狀態,並且能夠提供初始狀態,在表單操作後返回新的狀態。
表單狀態是上次提交表單時操作返回的值。如果尚未提交表單,則會是傳遞的初始狀態。
基本範例:
const [state, formAction] = useActionState(fn, initialState, permalink?);
<form>
元素的 action
或 formAction
props。補充: 什麼是漸進式增強(Progressive Enhancement) ?
漸進式增強(Progressive Enhancement)是一種網頁開發的設計策略,目的是確保網頁和應用程式能夠在各種環境中正常運作,無論是基本的舊設備或現代的高端設備,使用者都能獲得良好的體驗。
說明範例:
import { useActionState } from "react";
async function increment(previousState, formData) {
return previousState + 1;
}
function StatefulForm({}) {
const [state, formAction] = useActionState(increment, 0);
return (
<form>
{state}
<button formAction={formAction}>Increment</button>
</form>
);
}
useFormStatus
是 React 19 的 Hook,用來取得父層 <form>
的狀態,而不需要使用 props
傳遞。
基本範例:
const { pending, data, method, action } = useFormStatus();
<form>
正在提交的數據。如果沒有活動提交或沒有父層 <form>
,則會是 null
。<form>
上的 action prop 的函數,如果沒有action
的 props 或傳入的是 URI,或是沒有父層 <form>
,則都會是 null
。需要特別注意,useFormStatus
需要在 <form>
內部的子元件使用,useFormStatus
只會返回返回該父層 <form>
的狀態資訊,不會返回在同一元件或子元件中的任何 <form>
的狀態資訊。使用範例會像下面這樣。
function Form() {
//這是 useFormStatus 追蹤的 form
return (
<form action={submit}>
{/* ...其他表單元素 */}
<Submit />
</form>
);
}
function Submit() {
// 這樣使用才是有效的
const { pending } = useFormStatus();
return <button disabled={pending}>submit</button>;
}
參考資料:
https://react.dev/blog/2024/04/25/react-19
https://19.react.dev/reference/rsc/server-functions
https://19.react.dev/reference/react/useActionState
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/form
https://developer.mozilla.org/zh-CN/docs/Glossary/Progressive_Enhancement